package roaring

import (
	
	
	
)

const (
	arrayDefaultMaxSize        = 4096 // containers with 4096 or fewer integers should be array containers.
	arrayLazyLowerBound        = 1024
	maxCapacity                = 1 << 16
	serialCookieNoRunContainer = 12346 // only arrays and bitmaps
	invalidCardinality         = -1
	serialCookie               = 12347 // runs, arrays, and bitmaps
	noOffsetThreshold          = 4

	// MaxUint32 is the largest uint32 value.
	MaxUint32 = math.MaxUint32

	// MaxRange is One more than the maximum allowed bitmap bit index. For use as an upper
	// bound for ranges.
	MaxRange uint64 = MaxUint32 + 1

	// MaxUint16 is the largest 16 bit unsigned int.
	// This is the largest value an interval16 can store.
	MaxUint16 = math.MaxUint16

	// Compute wordSizeInBytes, the size of a word in bytes.
	_m              = ^uint64(0)
	_logS           = _m>>8&1 + _m>>16&1 + _m>>32&1
	wordSizeInBytes = 1 << _logS

	// other constants used in ctz_generic.go
	wordSizeInBits = wordSizeInBytes << 3 // word size in bits
)

const maxWord = 1<<wordSizeInBits - 1

// doesn't apply to runContainers
func getSizeInBytesFromCardinality( int) int {
	if  > arrayDefaultMaxSize {
		// bitmapContainer
		return maxCapacity / 8
	}
	// arrayContainer
	return 2 * 
}

func fill( []uint64,  uint64) {
	for  := range  {
		[] = 
	}
}
func fillRange( []uint64, ,  int,  uint64) {
	for  := ;  < ; ++ {
		[] = 
	}
}

func fillArrayAND( []uint16, ,  []uint64) {
	if len() != len() {
		panic("array lengths don't match")
	}
	// TODO: rewrite in assembly
	 := 0
	for  := range  {
		 := [] & []
		for  != 0 {
			 :=  & -
			[] = uint16((*64 + int(popcount(-1))))
			 =  + 1
			 ^= 
		}
	}
}

func fillArrayANDNOT( []uint16, ,  []uint64) {
	if len() != len() {
		panic("array lengths don't match")
	}
	// TODO: rewrite in assembly
	 := 0
	for  := range  {
		 := [] &^ []
		for  != 0 {
			 :=  & -
			[] = uint16((*64 + int(popcount(-1))))
			 =  + 1
			 ^= 
		}
	}
}

func fillArrayXOR( []uint16, ,  []uint64) {
	if len() != len() {
		panic("array lengths don't match")
	}
	// TODO: rewrite in assembly
	 := 0
	for  := 0;  < len(); ++ {
		 := [] ^ []
		for  != 0 {
			 :=  & -
			[] = uint16((*64 + int(popcount(-1))))
			 =  + 1
			 ^= 
		}
	}
}

func highbits( uint32) uint16 {
	return uint16( >> 16)
}
func lowbits( uint32) uint16 {
	return uint16( & maxLowBit)
}

const maxLowBit = 0xFFFF

func flipBitmapRange( []uint64,  int,  int) {
	if  >=  {
		return
	}
	 :=  / 64
	 := ( - 1) / 64
	[] ^= ^(^uint64(0) << uint(%64))
	for  := ;  < ; ++ {
		[] = ^[]
	}
	[] ^= ^uint64(0) >> (uint(-) % 64)
}

func resetBitmapRange( []uint64,  int,  int) {
	if  >=  {
		return
	}
	 :=  / 64
	 := ( - 1) / 64
	if  ==  {
		[] &= ^((^uint64(0) << uint(%64)) & (^uint64(0) >> (uint(-) % 64)))
		return
	}
	[] &= ^(^uint64(0) << uint(%64))
	for  :=  + 1;  < ; ++ {
		[] = 0
	}
	[] &= ^(^uint64(0) >> (uint(-) % 64))

}

func setBitmapRange( []uint64,  int,  int) {
	if  >=  {
		return
	}
	 :=  / 64
	 := ( - 1) / 64
	if  ==  {
		[] |= (^uint64(0) << uint(%64)) & (^uint64(0) >> (uint(-) % 64))
		return
	}
	[] |= ^uint64(0) << uint(%64)
	for  :=  + 1;  < ; ++ {
		[] = ^uint64(0)
	}
	[] |= ^uint64(0) >> (uint(-) % 64)
}

func flipBitmapRangeAndCardinalityChange( []uint64,  int,  int) int {
	 := wordCardinalityForBitmapRange(, , )
	flipBitmapRange(, , )
	 := wordCardinalityForBitmapRange(, , )
	return int( - )
}

func resetBitmapRangeAndCardinalityChange( []uint64,  int,  int) int {
	 := wordCardinalityForBitmapRange(, , )
	resetBitmapRange(, , )
	 := wordCardinalityForBitmapRange(, , )
	return int( - )
}

func setBitmapRangeAndCardinalityChange( []uint64,  int,  int) int {
	 := wordCardinalityForBitmapRange(, , )
	setBitmapRange(, , )
	 := wordCardinalityForBitmapRange(, , )
	return int( - )
}

func wordCardinalityForBitmapRange( []uint64,  int,  int) uint64 {
	 := uint64(0)
	if  >=  {
		return 
	}
	 :=  / 64
	 := ( - 1) / 64
	for  := ;  <= ; ++ {
		 += popcount([])
	}
	return 
}

func selectBitPosition( uint64,  int) int {
	 := 0

	// Divide 64bit
	 :=  & 0xFFFFFFFF
	 := popcount()
	if  <= uint64() {
		 =  >> 32
		 += 32
		 -= int()
	}
	 = 

	// Divide 32bit
	 =  & 0xFFFF
	 = popcount()
	if  <= uint64() {
		 =  >> 16
		 += 16
		 -= int()
	}
	 = 

	// Divide 16bit
	 =  & 0xFF
	 = popcount()
	if  <= uint64() {
		 =  >> 8
		 += 8
		 -= int()
	}
	 = 

	// Lookup in final byte
	var  uint
	for  = 0;  < 8; ++ {
		 -= int(( >> ) & 1)
		if  < 0 {
			break
		}
	}
	return  + int()

}

func panicOn( error) {
	if  != nil {
		panic()
	}
}

type ph struct {
	orig int
	rand int
}

type pha []ph

func ( pha) () int           { return len() }
func ( pha) (,  int) bool { return [].rand < [].rand }
func ( pha) (,  int)      { [], [] = [], [] }

func getRandomPermutation( int) []int {
	 := make([]ph, )
	for  := 0;  < ; ++ {
		[].orig = 
		[].rand = rand.Intn(1 << 29)
	}
	sort.Sort(pha())
	 := make([]int, )
	for  := range  {
		[] = [].orig
	}
	return 
}

func minOfInt(,  int) int {
	if  <  {
		return 
	}
	return 
}

func maxOfInt(,  int) int {
	if  >  {
		return 
	}
	return 
}

func maxOfUint16(,  uint16) uint16 {
	if  >  {
		return 
	}
	return 
}

func minOfUint16(,  uint16) uint16 {
	if  <  {
		return 
	}
	return 
}